# !/usr/bin/env python
# -*- coding:utf-8 -*-
"""
功能：2.1 节
版本：2022-04-02 22:00 创建
"""
import array
import collections
import timeit

import math
import traceback
import unittest

import numpy


class Section001TestCase(unittest.TestCase):
    def test_001(self):
        self.assertListEqual([1, 2, 3], [i for i in range(1, 4)])
        self.assertListEqual([1, 2, 3], list((i for i in range(1, 4))))

    def test_002(self):
        set_up = """
symbols = '$¢£¥€¤'
def non_ascii(c):
    return c > 127
"""

        def clock(label, cmd):
            res = timeit.repeat(cmd, setup=set_up, number=10000)
            print(label, *(f'{x:.3f}' for x in res))

        clock('listcomp        :', '[ord(s) for s in symbols if ord(s) > 127]')
        clock('listcomp + func :', '[ord(s) for s in symbols if non_ascii(ord(s))]')
        clock('filter + lambda :', 'list(filter(lambda c: c > 127, map(ord, symbols)))')
        clock('filter + func   :', 'list(filter(non_ascii, map(ord, symbols)))')

    def test_003(self):
        a = 1
        b = 2
        self.assertEqual(1, a)
        self.assertEqual(2, b)
        b, a = a, b  # 交换 a,b 的值
        self.assertEqual(2, a)
        self.assertEqual(1, b)

        a1, a2, a3 = (1, 2, 3)
        self.assertEqual(1, a1)
        self.assertEqual(2, a2)
        self.assertEqual(3, a3)

        a1, *a2 = (1, 2, 3)
        self.assertEqual(1, a1)
        self.assertListEqual([2, 3], a2)

        # * 运算符把一个可迭代对象拆开作为函数的参数
        self.assertEqual(3, max(*(1, 2, 3)))

        # 嵌套元组拆包
        (a1, (a2, a3)) = (1, (2, 3))
        self.assertEqual(1, a1)
        self.assertEqual(2, a2)
        self.assertEqual(3, a3)

        # 国际化软件时_可能就不是一个理想的占位符，因为它是 gettext.gettext 函数的常用别名
        a1, _ = (1, 2)

    def test_004(self):
        City = collections.namedtuple('City', 'name country population coordinates')
        tokyo = City('Tokyo', 'JP', 36.933, (35.689722, 139.691667))
        self.assertEqual('Tokyo', tokyo.name)
        self.assertEqual('JP', tokyo.country)
        self.assertAlmostEqual(36.933, tokyo.population, delta=0.001)
        self.assertAlmostEqual(35.689722, tokyo.coordinates[0], delta=0.00001)
        self.assertAlmostEqual(139.691667, tokyo.coordinates[1], delta=0.00001)

        self.assertTupleEqual(('name', 'country', 'population', 'coordinates'), City._fields)
        delhi_data = ('Delhi NCR', 'IN', 21.935, (28.613889, 77.208889))
        delhi = City._make(delhi_data)
        self.assertEqual('Delhi NCR', delhi.name)
        self.assertEqual('IN', delhi.country)
        print(delhi._asdict())

    def test_005(self):
        """切片"""
        data1 = '0123456789abcdefe'
        self.assertEqual('012', data1[:3])
        self.assertEqual(5 - 2, len(data1[2:5]))
        self.assertEqual(data1, data1[:5] + data1[5:])
        self.assertEqual('3210', data1[3::-1])
        self.assertEqual('321', data1[3:0:-1])
        self.assertEqual('', data1[3:-1:-1])

        # 多维切片
        data2 = numpy.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]])
        self.assertEqual(9, data2[2, 2])
        self.assertListEqual([[6], [9]], data2[1:3, 2:3].tolist())
        self.assertListEqual([[7, 8, 9], [10, 11, 12]], data2[2:].tolist())
        self.assertListEqual([7, 8, 9], data2[2, ...].tolist())
        self.assertListEqual([7, 8, 9], data2[2, :].tolist())

        # 切片赋值
        data3 = list('12345678')
        self.assertListEqual(['1', '2', '3', '4', '5', '6', '7', '8'], data3)

        data3[2:5] = ['a', 'b', 'c']
        self.assertListEqual(['1', '2', 'a', 'b', 'c', '6', '7', '8'], data3)

        data3[2:5] = ['3', '5']
        self.assertListEqual(['1', '2', '3', '5', '6', '7', '8'], data3)

        del data3[2:5]
        self.assertListEqual(['1', '2', '7', '8'], data3)

    def test_006(self):
        data1 = [['-'] * 3] * 3
        data2 = [['-'] * 3, ['-'] * 3, ['-'] * 3]
        self.assertListEqual([['-', '-', '-'], ['-', '-', '-'], ['-', '-', '-']], data1)
        self.assertListEqual(data1, data2)

        data1[0][0] = '+'
        data2[0][0] = '+'
        self.assertListEqual([['+', '-', '-'], ['+', '-', '-'], ['+', '-', '-']], data1)
        self.assertListEqual([['+', '-', '-'], ['-', '-', '-'], ['-', '-', '-']], data2)

    def test_007(self):
        data1 = (1, 2, [3, 4])
        try:
            data1[2] += [5, 6]
            # 改成data1[2].extend([5, 6]) 就能避免这个异常。
        except TypeError as e:
            print(data1)  # (1, 2, [3, 4, 5, 6])
            traceback.print_exc()  # TypeError: 'tuple' object does not support item assignment
        self.assertTupleEqual((1, 2, [3, 4, 5, 6]), data1)

    def test_008(self):
        # 内存视图
        data1 = array.array('h', [-2, -1, 0, 1, 2])
        data2 = memoryview(data1)
        self.assertEqual(len(data1), len(data1))
        self.assertEqual(data1[2], data2[2])
        data3 = data2.cast('B')
        self.assertListEqual([254, 255, 255, 255, 0, 0, 1, 0, 2, 0], data3.tolist())
        data3[5] = 4
        self.assertListEqual([-2, -1, 1024, 1, 2], data1.tolist())

    def test_009(self):
        queue1 = collections.deque(range(5), maxlen=10)
        self.assertSequenceEqual([0, 1, 2, 3, 4], queue1)
        # 队列的旋转操作，当 n > 0 时，队列的最右边的n个元素会被移动到队列的左边。当 n < 0 时，最左边的n个元素会被移动到右边。
        queue1.rotate(2)
        self.assertSequenceEqual([3, 4, 0, 1, 2, ], queue1)
        queue1.rotate(-3)
        self.assertSequenceEqual([1, 2, 3, 4, 0, ], queue1)

        queue1.append(5)
        queue1.appendleft(6)
        self.assertSequenceEqual([6, 1, 2, 3, 4, 0, 5, ], queue1)

        queue1.extend([7])
        queue1.extendleft([8])
        self.assertSequenceEqual([8, 6, 1, 2, 3, 4, 0, 5, 7], queue1)

        # 当试图对一个已满（len(d) == d.maxlen）的队列做尾部添加操作的时候，它头部的元素会被删除掉。
        queue1.extend([9, 10, 11])
        self.assertSequenceEqual([1, 2, 3, 4, 0, 5, 7, 9, 10, 11], queue1)


if __name__ == '__main__':
    unittest.main()
